/*
This is part of Screenbar, which is based in part on the Litestep
shell source code.

Copyright (C) 2008-2009 Jim Babcock
Copyright (C) 1997-2009 The LiteStep Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "stdafx.h"

TextLabelElement::TextLabelElement(string prefix)
	:LayoutElement(prefix)
{
	alignHoriz = parseAlign(getConfigString("AlignHoriz", "center", prefix.c_str()));
	alignVert  = parseAlign(getConfigString("AlignVert", "center", prefix.c_str()));
	
	string defaultX, defaultY;
	switch(alignHoriz) {
		case alignLeft:   defaultX = "0"; break;
		case alignCenter: defaultX = "50%"; break;
		case alignRight:  defaultX = "-0"; break;
	}
	switch(alignVert) {
		case alignTop:    defaultY = "0"; break;
		case alignCenter: defaultY = "50%"; break;
		case alignBottom: defaultY = "-0"; break;
	}
	
	x = getConfigString("X", defaultX.c_str(), prefix.c_str());
	y = getConfigString("Y", defaultY.c_str(), prefix.c_str());
	minLength = getConfigString("MinLength", "0", prefix.c_str());
	maxLength = getConfigString("MaxLength", "250", prefix.c_str());
	
	allowAbbrev = getConfigBool("AllowAbbrev", false, prefix.c_str());
	
	useStatsClass = getConfigBool("UseXStats", false, prefix.c_str());
	
#ifdef USE_LSPAINT
	font = LSPaint_CreateTextPainter(prefix.c_str(), NULL);
#else
	PaintTextDefaults textDefaults;
	textDefaults.m_iFontHeight = 8;
	
	font = Create_xTextClass();
	font->configure(prefix.c_str(), "", FALSE, NULL, &textDefaults);
#endif
	
	string textString = getConfigString("Text", ".auto", prefix.c_str());
	if(textString == ".auto")
		text = labelAuto;
	else if(textString == ".desknum")
		text = labelDeskNum;
	else if(textString == ".taskname")
		text = labelTaskName;
	else if(textString == ".pid")
		text = labelTaskPID;
	else if(textString == ".cpu")
		text = labelTaskCPU;
	else if(textString == ".mem")
		text = labelTaskMem;
	else {
		text = labelCustom;
		customText = textString;
	}
}

TextLabelElement::~TextLabelElement()
{
#ifdef USE_LSPAINT
	LSPaint_FreeTextPainter(font);
#else
	Destroy_xTextClass(font);
#endif
}

string TextLabelElement::getText(const ElementContext *context)
{
	if(useStatsClass)
	{
		return statsClassEval(customText, context);
	}
	
	switch(text)
	{
		default:
		case labelAuto: {
			WindowData *taskWindow = context->getTask();
			if(taskWindow)
				return taskWindow->getTitle();
			else if(context->desk)
				return context->desk->getLabel();
			else
				return "?";
		}
				
		case labelTaskName: {
			WindowData *taskWindow = context->getTask();
			if(taskWindow)
				return taskWindow->getTitle();
			else
				return "?";
		}
			
		case labelDeskNum:
			if(context->desk)
				return context->desk->getLabel();
			else
				return "?";
			
		case labelTaskPID: {
			WindowData *taskWindow = context->getTask();
			if(taskWindow)
				return retprintf("%i", taskWindow->pid);
			else
				return "?";
		}
			
		case labelTaskCPU: {
			WindowData *taskWindow = context->getTask();
			if(!taskWindow)
				return "?";
			ProcessData *process = processTracker->getProcess(taskWindow->pid);
			
			if(process)
				return retprintf("%i", (int)(process->getCPUUsage()*100));
			else
				return "?";
		}
		
		case labelTaskMem: {
			WindowData *taskWindow = context->getTask();
			if(!taskWindow)
				return "?";
			ProcessData *process = processTracker->getProcess(taskWindow->pid);
			
			if(process)
				return retprintf("%i", (int)(process->getMemUsage() / 1024));
			else
				return "?";
		}
			
		case labelCustom:
			return customText;
	}
}

SIZE TextLabelElement::measureText(const LayoutCacheNode *node, const string &text)
{
	ScreenbarWindow *window = node->context.window;
	HDC drawContext = window->getDrawContextForSize();
	assert(drawContext != NULL);
	
#ifdef USE_LSPAINT
	SIZE textSize = LSPaint_MeasureTextA(font, text.c_str(), drawContext, 0);
#else
	POINT ptTextSize = font->measure(drawContext, 0, 0, text.c_str());
	SIZE textSize = {ptTextSize.x, ptTextSize.y};
#endif
	
	return textSize;
}

void TextLabelElement::draw(HDC drawContext, const LayoutCacheNode *node)
{
	string text = getText(&node->context);
	Rect rect = node->boundingRect;
	
	SIZE textSize = measureText(node, text);
	
	switch(alignHoriz)
	{
		default:
		case alignLeft: {
			int offsetX = ParseCoordinate(x.c_str(), 0, rect.width);
			rect.left += offsetX;
			rect.width -= offsetX;
			break;
		}
		case alignRight: {
			int rightX = ParseCoordinate(x.c_str(), rect.width, rect.width);
			int leftX = rightX - textSize.cx;
			if(leftX < 0) leftX = 0;
			rect.left += leftX;
			rect.width = rightX - leftX;
			break;
		}
		case alignCenter: {
			int offsetX = ParseCoordinate(x.c_str(), 0, rect.width) - textSize.cx/2;
			if(offsetX > 0) {
				rect.left += offsetX;
				rect.width -= offsetX;
			}
			break;
		}
	}
	
	switch(alignVert)
	{
		default:
		case alignTop: {
			int offsetY = ParseCoordinate(y.c_str(), 0, rect.height);
			rect.top += offsetY;
			rect.height = textSize.cy;
			break;
		}
		case alignBottom: {
			int bottomY = ParseCoordinate(y.c_str(), rect.height, rect.height);
			int topY = bottomY - textSize.cy;
			if(topY < 0) topY = 0;
			rect.top += topY;
			rect.height = bottomY - topY;
			break;
		}
		case alignCenter: {
			int offsetY = ParseCoordinate(y.c_str(), 0, rect.height) - textSize.cy/2;
			if(offsetY > 0) {
				rect.top += offsetY;
				rect.height = textSize.cy;
			}
			break;
		}
	}
	
#ifdef USE_LSPAINT
	LSPaint_PaintTextA(font, drawContext, rect, text.c_str());
#else
	font->apply(drawContext,
		rect.left, rect.top,
		rect.width, rect.height,
		text.c_str());
#endif
}

bool TextLabelElement::changed(const LayoutCacheNode *node)
{
	if(!node->elementData || getText(&node->context) != (char*)node->elementData)
		return true;
	return LayoutElement::changed(node);
}

void TextLabelElement::update(LayoutCacheNode *node)
{
	if(node->elementData)
		delete[] (char*)node->elementData;
	
	node->elementData = (void*)_strdup(getText(&node->context).c_str());
}

void TextLabelElement::deleteElementData(LayoutCacheNode *node, void *elementData)
{
	char *text = (char*)elementData;
	delete[] text;
}

ElementSize TextLabelElement::getLength(const LayoutCacheNode *node)
{
	string text = getText(&node->context);
	SIZE textSize = measureText(node, text);
	
	int minSize, preferredSize;
	int maxSize;
	if(node->context.vertical) {
		int contextHeight = node->boundingRect.height;
		/*minSize = ParseCoordinate(minLength.c_str(), textSize.y, contextHeight);
		preferredSize = max(minSize, textSize.y);
		maxSize = ParseCoordinate(maxLength.c_str(), contextHeight, contextHeight);*/
		
		minSize = preferredSize = textSize.cy;
	} else {
		int contextWidth = node->boundingRect.width;
		minSize = ParseCoordinate(minLength.c_str(), textSize.cx, contextWidth);
		preferredSize = max(minSize, textSize.cx);
		maxSize = ParseCoordinate(maxLength.c_str(), contextWidth, contextWidth);
	}
	
	if(maxSize < minSize)
		maxSize = minSize;
	if(preferredSize > maxSize)
		preferredSize = maxSize;
	
	if(!allowAbbrev)
	{
		minSize = preferredSize;
	}
	
	return ElementSize(minSize, preferredSize);
}
